﻿using Dubbo.Config.Api;
using Spring.Context;
using Spring.Context.Events;
using Spring.Context.Support;
using Spring.Objects.Factory;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Dubbo.Config.Spring
{
    public class ServiceObject<T> : ServiceConfig<T>,
        IInitializingObject, IApplicationContextAware, IObjectNameAware, IApplicationEventListener, IDisposable
    {
        private static IApplicationContext SPRING_CONTEXT;

        private IApplicationContext applicationContext;

        private string objectName;

        private bool supportedApplicationListener;

        public string ObjectName
        {
            set
            {
                this.objectName = value;
            }
        }

        public static IApplicationContext GetSpringContext()
        {
            return SPRING_CONTEXT;
        }

        public IApplicationContext ApplicationContext
        {
            set
            {
                this.applicationContext = value;
                SpringExtensionFactory.AddApplicationContext(applicationContext);
                if (applicationContext != null)
                {
                    SPRING_CONTEXT = applicationContext;
                    try
                    {
                        applicationContext.Subscribe(this);
                        supportedApplicationListener = true;
                    }
                    catch (Exception ex)
                    {
                    }
                }
            }
        }


        public void AfterPropertiesSet()
        {
            if (Provider == null)
            {
                var providerConfigMap = applicationContext == null ? null : ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(applicationContext, typeof(ProviderConfig), false, false);
                if (providerConfigMap != null && providerConfigMap.Count > 0)
                {
                    ProviderConfig providerConfig = null;
                    foreach (ProviderConfig config in providerConfigMap.Values)
                    {
                        if (config.IsDefault == null || config.IsDefault.Value)
                        {
                            if (providerConfig != null)
                            {
                                throw new Exception("Duplicate provider configs: " + providerConfig + " and " + config);
                            }
                            providerConfig = config;
                        }
                    }
                    if (providerConfig != null)
                    {
                        Provider = providerConfig;
                    }
                }
            }
            if (Application == null && (Provider == null || Provider.Application == null))
            {
                var applicationConfigMap = applicationContext == null ? null : ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(applicationContext, typeof(ApplicationConfig), false, false);
                if (applicationConfigMap != null && applicationConfigMap.Count > 0)
                {
                    ApplicationConfig applicationConfig = null;
                    foreach (ApplicationConfig config in applicationConfigMap.Values)
                    {
                        if (config.IsDefault == null || config.IsDefault.Value)
                        {
                            if (applicationConfig != null)
                            {
                                throw new Exception("Duplicate application configs: " + applicationConfig + " and " + config);
                            }
                            applicationConfig = config;
                        }
                    }
                    if (applicationConfig != null)
                    {
                        Application = applicationConfig;
                    }
                }
            }
            if ((Protocols == null || Protocols.Count == 0)
                && (Provider == null || Provider.Protocols == null || Provider.Protocols.Count == 0))
            {
                var protocolConfigMap = applicationContext == null ? null : ObjectFactoryUtils.ObjectsOfTypeIncludingAncestors(applicationContext, typeof(ProtocolConfig), false, false);
                if (protocolConfigMap != null && protocolConfigMap.Count > 0)
                {
                    List<ProtocolConfig> protocolConfigs = new List<ProtocolConfig>();
                    foreach (ProtocolConfig config in protocolConfigMap.Values)
                    {
                        if (config.IsDefault == null || config.IsDefault.Value)
                        {
                            protocolConfigs.Add(config);
                        }
                    }
                    if (protocolConfigs != null && protocolConfigs.Count() > 0)
                    {
                        Protocols = protocolConfigs;
                    }
                }
            }
            if (string.IsNullOrEmpty(Path))
            {
                if (!string.IsNullOrEmpty(objectName) && !string.IsNullOrEmpty(Interface)
                    && objectName.StartsWith(Interface))
                {
                    Path = objectName;
                }
            }
            if (!IsDelay())
            {
                Export();
            }
        }

        public void HandleApplicationEvent(object sender, ApplicationEventArgs e)
        {
            if (e is ContextRefreshedEventArgs)
            {
                if (IsDelay() && !IsExported && !IsUnexported)
                {
                    //if (logger.isInfoEnabled())
                    //{
                    //    logger.info("The service ready on spring started. service: " + getInterface());
                    //}
                    Export();
                }
            }
        }

        private bool IsDelay()
        {
            int? delay = Delay;
            ProviderConfig provider = Provider;
            if (delay == null && provider != null)
            {
                delay = provider.Delay;
            }
            return supportedApplicationListener && (delay == null || delay.Value == -1);
        }

        public void Dispose()
        {
            Unexport();
        }
    }
}
